﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.ComponentModel.Composition;
using Seesmic.Sdp.Extensibility;
using Seesmic.Sdp.Utils;

using System.Xml.Serialization;

using System.Xml;
using System.Text;
using System.IO;

/*using TweetSharp.Twitter.Fluent;
using TweetSharp.Model;
using TweetSharp.Twitter.Model;
using TweetSharp.Twitter.Extensions;
using Seesmic.Sdp.Plugins.Twitter;*/

using PTiRouZ.Net.SilverLight.Api.HelloTipi;


namespace Seesmic.HelloTipi
{
    [Export(typeof(IAccountProvider))]
    public class HelloTipiAccountProvider : IAccountProvider
    {
        private bool _sessionExists;

        //public static readonly Guid HelloTipiAccountProviderId = new Guid("AE8B66F6-37BE-4655-BF9C-C1B8CB4D61CE");
        public static readonly Guid HelloTipiAccountProviderId = new Guid("FD3B5665-4A0F-4571-9E67-62952D862B6F");

        #region IAccountProvider Members

        public DataTemplate AccountIcon
        {
            get
            {
                return HelloTipiPlugin.AccountIcon;
            }
        }

        public string AccountTypeName
        {
            get { return "HelloTipi"; }
        }

        public void AuthenticateAsync(IAccount account, object userState, AsyncCompletedCallback completedCallback)
        {
            //HelloTipiPlugin.LogInfo("AuthenticateAsync - account : " + account.ToString());

            DialogNotificationInfo info = new DialogNotificationInfo();
            info.Title = string.Format("Authentification {0} ", account.Username);
            info.Text = "Connection au serveur...";
            info.Buttons = DialogNotificationButtons.Cancel;
            DialogNotificationInfo notificationInfo = info;

            HelloTipiPlugin.NotifyService.ShowDialogNotification(notificationInfo);

            AuthenticationAsyncToken asynkToken = new AuthenticationAsyncToken((HelloTipiAccount)account);

            notificationInfo.Dismissed += delegate(object sender, EventArgs args)
            {
                if (notificationInfo.DialogResult == true)
                {
                    asynkToken.Cancel();
                }
            };
                          
            asynkToken.ResponseReceived += delegate(object sender, EventArgs e)
            {
                //HelloTipiPlugin.LogInfo("AuthenticateAsync event ResponseReceived");
                SynchronizationHelper.Post<object>(delegate(object param)
                {
                    AuthenticationAsyncToken token = (AuthenticationAsyncToken)param;
                              
                    switch (token.Response)
                    {
                        case AuthenticationAsyncTokenResponses.Success:      
                            completedCallback(this, new AsyncCompletedEventArgs(null, false, userState));
                            notificationInfo.Dismiss();                            
                            return;

                        case AuthenticationAsyncTokenResponses.Failed:
                            completedCallback(this, new AsyncCompletedEventArgs(new Exception(token.Message), false, userState));
                            notificationInfo.Dismiss();
                            return;

                        case AuthenticationAsyncTokenResponses.Cancel:
                            completedCallback(this, new AsyncCompletedEventArgs(null, true, userState));
                            return;
                    }
                    completedCallback(this, new AsyncCompletedEventArgs(new Exception(token.Message), false, userState));

                    notificationInfo.Dismiss();
                }, sender);
            };

            asynkToken.Authenticate();            
        }

        public IAccount CreateAccount()
        {
            if (!this._sessionExists)
            {
                HelloTipiAccount ac = new HelloTipiAccount();
               // HelloTipiPlugin.LogInfo("AccountProvider, CreateAccount : " + ac.ToString());
                return ac;
            }
            return null;
        }

        public IAccount DeserializeAccount(string data)
        {
            try
            {
                System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(HelloTipiAccount));
                return (HelloTipiAccount)serializer.Deserialize(new StringReader(data));
            }
            catch (Exception)
            {
                return null;
            }
        }

        public DataTemplate EditAccountTemplate
        {
            get { return HelloTipiPlugin.EditAccountTemplate; }
        }

        public ISession GetSession(IAccount account)
        {
            this._sessionExists = true;
            //HelloTipiPlugin.LogInfo("GetSession - account : " + account.ToString());
            return new HelloTipiSession((HelloTipiAccount)account);
        }

        public Guid Id
        {
            get { return HelloTipiAccountProviderId; }
        }

        public DataTemplate NewAccountTemplate
        {            
            get
            {
                if (!this._sessionExists)
                    return HelloTipiPlugin.NewAccountTemplate;
                else
                    return HelloTipiPlugin.OneAccountOnly;
                //return (DataTemplate)_Resources["NewAccountTemplate"];
            }

            //get { return new DataTemplate(); } // Seesmic.HelloTipi.NewAccountTemplate;
        }

        public string SerializeAccount(IAccount account)
        {
            //HelloTipiPlugin.LogInfo("SerializeAccount");
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(HelloTipiAccount));
            StringBuilder output = new StringBuilder();
            XmlWriter xmlWriter = XmlWriter.Create(output);
            serializer.Serialize(xmlWriter, account);
            return output.ToString();
        }

        #endregion



        private class AuthenticationAsyncToken
        {
            private HelloTipiAccount Account;
            private bool HasResponse;
            public string Message;

            public HelloTipiAccountProvider.AuthenticationAsyncTokenResponses Response;

            public EventHandler ResponseReceived;

            public AuthenticationAsyncToken(HelloTipiAccount account)
            {
                this.Account = account;
                this.HasResponse = false;
                this.Response = HelloTipiAccountProvider.AuthenticationAsyncTokenResponses.None;
            }

            public void Cancel()
            {
                this.OnCancelled();
            }

            private void OnCancelled()
            {
                this.Response = HelloTipiAccountProvider.AuthenticationAsyncTokenResponses.Cancel;
            }

            private void OnFailed(string Message = null)
            {
                this.Message = string.Format("Echec de l'authentification pour l'utilisateur {0} !", this.Account.Username);
                if (Message != null)
                    this.Message += String.Format("Message d'erreur : {0}", Message);

                this.Response = HelloTipiAccountProvider.AuthenticationAsyncTokenResponses.Failed;
            }

            private void OnSuccess()
            {
                
                this.Response = HelloTipiAccountProvider.AuthenticationAsyncTokenResponses.Success;
                this.RaiseResponseReceived();
            }

            public void Authenticate()
            {
                apitxt h = new apitxt(this.Account.Username, this.Account.Password);

                h.VerifyCredentialsCompleted += delegate(object sender, VerifyCredentialsEventArgs e)
                    {
                        //HelloTipiPlugin.LogInfo("Authenticate event VerifyCredentialsCompleted : " + this.Account.ToString());

                        if (e.result != null)
                        {
                            this.Account.ScreenName = e.result.screen_name;
                            this.Account.UrlAvatar = e.result.profile_image_url;
                            this.Account.UserID = e.result.id;
                            this.OnSuccess();
                        }
                        else
                            this.OnFailed();
                    };

                try
                {
                    h.verify_credentials();
                }
                catch (Exception e)
                {
                    this.OnFailed(e.Message);
                }
            }

            private void RaiseResponseReceived()
            {
                if (this.ResponseReceived != null)
                {                    
                    this.HasResponse = true;
                    this.ResponseReceived(this, new EventArgs());
                }
            }

        }
        /*private class AuthenticationAsyncToken
        {
            private IFluentTwitter _VerifyRequest;
            private HelloTipiAccount Account;
            private bool HasResponse;
            public string Message;
            public HelloTipiAccountProvider.AuthenticationAsyncTokenResponses Response;
            public EventHandler ResponseReceived;

            public AuthenticationAsyncToken(HelloTipiAccount account)
            {
                this.Account = account;
                this.HasResponse = false;
                this.Response = HelloTipiAccountProvider.AuthenticationAsyncTokenResponses.None;
            }

            public void Cancel()
            {
                if (this._VerifyRequest != null)
                {
                    this._VerifyRequest.Cancel();
                }
                this.OnCancelled();
            }

            private void OnCancelled()
            {
                this.Response = HelloTipiAccountProvider.AuthenticationAsyncTokenResponses.Cancel;
                this.RaiseResponseReceived();
            }

            private void OnFailed()
            {
                this.Message = string.Format("Failed to authenticate {0}!", this.Account.Username);
                this.Response = HelloTipiAccountProvider.AuthenticationAsyncTokenResponses.Failed;
            }

            private void OnSuccess()
            {
                this.Response = HelloTipiAccountProvider.AuthenticationAsyncTokenResponses.Success;
                this.RaiseResponseReceived();
            }

            private void RaiseResponseReceived()
            {
                if (this.ResponseReceived != null)
                {
                    this.HasResponse = true;
                    this.ResponseReceived(this, new EventArgs());
                }
            }

            public void Authenticate()
            {
                Action<object, TwitterResult> result = null;
                try
                {
                    IFluentTwitter root = HelloTipiAdapter.CreateRequest();
                    root.Configuration.UseGzipCompression().Configuration.UseTransparentProxy("https://api.twitter.com/oauth/{0}").Authentication.GetClientAuthAccessToken(this.Account.Username, this.Account.Password);
                    if (result == null)
                    {
                        result = delegate(object o, TwitterResult HelloTipiResult)
                        {
                            Action<object, TwitterResult> action = null;
                            if (HelloTipiResult.IsTwitterError || HelloTipiResult.IsNetworkError)
                            {
                                this.OnFailed();
                            }
                            else
                            {
                                OAuthToken token = HelloTipiResult.AsToken();
                                if (token == null)
                                {
                                    this.OnFailed();
                                }
                                else
                                {
                                    this.Account.Token = token.Token;
                                    this.Account.Password = token.TokenSecret;
                                    this._VerifyRequest = HelloTipiAdapter.CreateRequest();
                                    if (action == null)
                                    {
                                        action = delegate(object ao, TwitterResult authResult)
                                        {
                                            if (authResult.IsTwitterError || authResult.IsNetworkError)
                                            {
                                                this.OnFailed();
                                            }
                                            else
                                            {
                                                this.OnSuccess();
                                            }
                                        };
                                    }
                                    this._VerifyRequest.AuthenticateWith(this.Account.Token, this.Account.Password).Account().VerifyCredentials().Request(null, action);
                                }
                            }
                        };
                    }
                    root.Request(null, result);
                }
                catch (Exception exception)
                {
                    TwitterPlugin.LogService.Warning("Failed to authenticate due to exception. See details.", exception);
                    this.OnFailed();
                }
            }
        }*/

        private enum AuthenticationAsyncTokenResponses
        {
            Success,
            Failed,
            ConnectionTimeout,
            Cancel,
            None
        }
    }
}